﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.ESGRatings.BusinessLogic.ESGOnlineReport;
using Sustainalytics.Utils;
using System.Threading;
using MongoDB.Driver;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.DataLayer;
using Sustainalytics.BusinessResearchProductStates.Entities.ResearchState;
using Sustainalytics.Entities;
using Sustainalytics.ESG.Entities;
using ThemePerformance = Sustainalytics.ClientDW.Entities.ThemePerformance;

namespace Sustainalytics.ReportGenerator.BL
{
    public class GeneratePdfBulkReader
    {
        private int _skipEsg;
        private readonly int _bulkSizeEsg;

        private int _skipFocusedRatings;
        private readonly int _bulkSizeFocusedRatings;

        private int _skipControversy;
        private readonly int _bulkSizeControversy;

        private readonly string _clientDwUrl;
    
        private readonly Guid[] _requestedCompanies;

        private readonly CancellationToken _cancelToken;
        private readonly int _maxDegreeOfParallelism;
        private readonly Action<string> _logAction;

        private readonly IRepositoryCollection<SubPeerGroupKeyEsgIssue> _rep;
        private readonly IRepositoryCollection<Analyst> _analystRepo;
        private readonly IRepositoryCollection<IndicatorTemplate> _repIndicaorTemplate;
        private readonly IRepositoryCollection<CorporateData> _repCorporateData;
        private readonly IRepositoryCollection<FinancialData> _repFinancialData; 
        private readonly IRepositoryCollection<RPCompanyProfile> _repRPCompanyProfile;
        private readonly IRepositoryCollection<RPCompanyESGComputationResult> _repRPCompanyESGComputationResult;
        private readonly IHistoricalDataBusinessLogicUnit _historycalDataManager;
        private readonly IRepositoryCollection<RPIndicatorExtended> _repRPIndicatorExt;
        private readonly IRepositoryCollection<RPControversyIndicator> _repRPControversyInd;
        private readonly IRepositoryCollection<ComparisonGroupControversy> _repCompGroupControversy;
        private readonly IRepositoryCollection<EventIndicator> _repEventIndicator;
        private readonly IRepositoryCollection<Incident> _repIncident;
        private readonly IRepositoryCollection<CompanyKeyESGIssue> _repCompanyESGIssue;
        private readonly IRepositoryCollection<Source> _repSource;

        public GeneratePdfBulkReader(
            IRepositoryCollection<SubPeerGroupKeyEsgIssue> rep,
            IRepositoryCollection<Analyst> analystRepo,
            IRepositoryCollection<IndicatorTemplate> repIndicaorTemplate,
            IRepositoryCollection<CorporateData> repCorporateData,
            IRepositoryCollection<FinancialData> repFinancialData,
            IRepositoryCollection<RPCompanyProfile> repRPCompanyProfile,
            IRepositoryCollection<RPCompanyESGComputationResult> repRPCompanyESGComputationResult,
            IHistoricalDataBusinessLogicUnit historycalDataManager,
            IRepositoryCollection<RPIndicatorExtended> repRPIndicatorExt,
            IRepositoryCollection<RPControversyIndicator> repRPControversyInd,
            IRepositoryCollection<ComparisonGroupControversy> repCompGroupControversy,
            IRepositoryCollection<EventIndicator> repEventIndicator,
            IRepositoryCollection<Incident> repIncident,
            IRepositoryCollection<CompanyKeyESGIssue> repCompanyESGIssue,
            IRepositoryCollection<Source> repSource,
            int bulkSize, IEnumerable<Guid> ids, string clientDwUrl,
            ESGProfile defaultEsgProfile, Action<string> log, CancellationToken cancelToken, Guid[] requestedCompanies = null, int maxDegreeOfParallelism = -1)
        {
            _logAction = log;
            _clientDwUrl = clientDwUrl;

            _skipEsg = 0;
            _bulkSizeEsg = bulkSize;
            _skipFocusedRatings = 0;
            _bulkSizeFocusedRatings = bulkSize;
            _skipControversy = 0;
            _bulkSizeControversy = bulkSize;

            _cancelToken = cancelToken;
            _maxDegreeOfParallelism = maxDegreeOfParallelism;

            if (_maxDegreeOfParallelism < 1)
                _maxDegreeOfParallelism = ParallelHelper.GetMaxDegreeOfParallelism();

            AllFinancialData = new Dictionary<Guid, FinancialData>();
            IndicatorTemplates = new List<IndicatorTemplate>();
            SubPeerGroupKeyEsgIssueDictionary = new Dictionary<int, List<SubPeerGroupKeyEsgIssue>>();
            _requestedCompanies = requestedCompanies;
            EsgDefaultProfile = defaultEsgProfile;
           
            _rep = rep;
            _analystRepo = analystRepo;
            _repIndicaorTemplate = repIndicaorTemplate;
            _repCorporateData = repCorporateData;
            _repFinancialData = repFinancialData;
            _repRPCompanyProfile = repRPCompanyProfile;
            _repRPCompanyESGComputationResult = repRPCompanyESGComputationResult;
            _historycalDataManager = historycalDataManager;
            _repRPIndicatorExt = repRPIndicatorExt;
            _repIncident = repIncident;
            _repRPControversyInd = repRPControversyInd;
            _repCompGroupControversy = repCompGroupControversy;
            _repEventIndicator = repEventIndicator;
            _repCompanyESGIssue = repCompanyESGIssue;
            _repSource = repSource;

        }

        public Dictionary<Guid, Analyst> AnalystsDictionary { get; set; }
        public Dictionary<Guid, FinancialData> AllFinancialData { get; set; }
        public IList<IndicatorTemplate> IndicatorTemplates { get; set; }
        public Dictionary<string, int> SubPeerGroupDictionary { get; set; }
        public Dictionary<int, List<SubPeerGroupKeyEsgIssue>> SubPeerGroupKeyEsgIssueDictionary { get; set; }
        public ESGProfile EsgDefaultProfile { get; protected set; }


        public void OneTimeDataRead()
        {
            // one time reading collections
            var readActions = new List<Action>();
            readActions.Add(FinancialData);
            readActions.Add(IndicatorTemplate);
            readActions.Add(Analyst);
            readActions.Add(SubIndustryKEI);
            readActions.RunInParallel(_cancelToken, _maxDegreeOfParallelism);
        }

        private void SubIndustryKEI()
        {
            var all = _rep.ReadAll();

            if (all == null) return;

            var list = all.GroupBy(x => x.SubPeerGroupId).ToList();
            list.ForEach(x => SubPeerGroupKeyEsgIssueDictionary.Add(x.Key, x.ToList()));
        }


        private void Analyst()
        {
            AnalystsDictionary = _analystRepo.ReadAll().ToDictionary(k => k.Id, v => v);
        }

        private void IndicatorTemplate()
        {
            IndicatorTemplates = _repIndicaorTemplate.ReadAll();
        }

        private void FinancialData()
        {

            Guid[] allIds;
            if (_requestedCompanies.IsNullOrEmpty())
            {
                allIds = _repCorporateData.ReadAllWhere(a => a.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable, includeFields: "Id")
                    .Select(x => x.Id).ToArray();
            }
            else
            {
                allIds = _repCorporateData.ReadAllWhere(a => a.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable && _requestedCompanies.Contains(a.Id), includeFields: "Id").Select(a => a.Id).ToArray();

            }

            AllFinancialData.Clear();

            var position = 0;
            for (;;)
            {
                var ids = allIds.Skip(position).Take(_bulkSizeEsg);
                position += _bulkSizeEsg;
                var dictionary = _repFinancialData.ReadbyIds(ids, new string[] { "MarketCapitalization", "CompanyName" });
                if (dictionary != null)
                {
                    foreach (var x in dictionary.Values)
                        AllFinancialData[x.Id] = x;
                }

                if (ids.Count() < _bulkSizeEsg || (ids.Count() == _bulkSizeEsg && _bulkSizeEsg == 1))
                    break;
            }
        }

        public IEnumerable<CompanyReportDataOffline> NextESGRatingsBulk()
        {
            IEnumerable<Guid> ids;
            IDictionary<Guid, CorporateData> cdDic = null;
            IDictionary<Guid, FinancialData> finDic = null;
            IDictionary<Guid, RPCompanyProfile> rpCompanyProfileDic = new Dictionary<Guid, RPCompanyProfile>();
            IDictionary<Guid, OverallPerformance> overallPerformanceDic = new Dictionary<Guid, OverallPerformance>();
            IDictionary<Guid, RPRelativePosition> companyRelativePositionDictionary = new Dictionary<Guid, RPRelativePosition>();
            IDictionary<Guid, RPIndicatorPerformance[]> companyIndicatorsPerformanceDictionary = new Dictionary<Guid, RPIndicatorPerformance[]>();
            IDictionary<Guid, List<ThemePerformance>> themesPerformanceDic = new Dictionary<Guid, List<ThemePerformance>>();

            IDictionary<Guid, CompanyHistoricalPerformance> companyHistoricalPerformanceDic = new Dictionary<Guid, CompanyHistoricalPerformance>();
            IDictionary<Guid, List<RPIndicatorExtended>> standardIndicatorsDic = new Dictionary<Guid, List<RPIndicatorExtended>>();
            IDictionary<Guid, List<RPControversyIndicator>> controversyIndicatorsDic = new Dictionary<Guid, List<RPControversyIndicator>>();
            IDictionary<Guid, List<ComparisonGroupControversy>> comparisonGroupControversiesDic = new Dictionary<Guid, List<ComparisonGroupControversy>>();
            IDictionary<Guid, List<EventIndicator>> eventIndicatorsDic = new Dictionary<Guid, List<EventIndicator>>();
            IDictionary<Guid, List<Incident>> incidentsDic = new Dictionary<Guid, List<Incident>>();
            IDictionary<Guid, List<KeyEsgIssue>> keyEsgIssuesDictionary = new Dictionary<Guid, List<KeyEsgIssue>>();
            IDictionary<Guid, int> subPeerGroupIdDictionary = new Dictionary<Guid, int>();
            IDictionary<Guid, List<Source>> companiesNonControversySources = new Dictionary<Guid, List<Source>>();

            if (IndicatorTemplates == null)
                OneTimeDataRead();

            var result = new ConcurrentBag<CompanyReportDataOffline>();

            IList<CorporateData> list;
            if (_requestedCompanies.IsNullOrEmpty())
            {
                list = _repCorporateData.ReadAllWhere(a => a.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable, _skipEsg, _bulkSizeEsg);
            }
            else
            {
                list = _repCorporateData.ReadAllWhere(a => a.ComprehensiveEsgResearchState.ResearchState == ResearchState.ResearchAvailable && _requestedCompanies.Contains(a.Id),
                    _skipEsg, _bulkSizeEsg);
            }
            if (list != null && list.Any())
            {
                cdDic = list.ToDictionary(x => x.Id);
                ids = cdDic.Keys.OrderBy(x => x);
                _skipEsg += _bulkSizeEsg;


                var readActions = new List<Action>();

                readActions.Add(() =>
                {
                    finDic = _repFinancialData.ReadbyIds(ids);
                });
                readActions.Add(() =>
                {
                    rpCompanyProfileDic = _repRPCompanyProfile.ReadbyIds(ids);
                });
                readActions.Add(() =>
                {
                    var rpPerformanceData =
                        _repRPCompanyESGComputationResult.ReadWhere(x => ids.Contains(x.Id), null,
                            null, null, x => x.Id, x => x.OverallPerformance, x => x.RelativePosition,
                            x => x.EnvironmentPerformance, x => x.SocialPerformance, x => x.GovernancePerformance,
                            x => x.PreparednessScore, x => x.DisclosureScore, x => x.QuantitativePerformanceScore, x => x.QualitativePerformanceScore,
                            x => x.Indicators, x => x.IsInReferenceUniverse);

                    overallPerformanceDic = rpPerformanceData.ToDictionary(x => x.Id, x => new OverallPerformance()
                    {
                        CompanyScore = (int)Math.Round(x.OverallPerformance.Score, MidpointRounding.AwayFromZero),
                        CompanyAssessment = new RPAssessment()
                        {
                            Id = x.OverallPerformance.Assessment.Id,
                            Name = x.OverallPerformance.Assessment.Name
                        },
                        CompanyRank = x.OverallPerformance.Rank.Value ?? 0,
                        CompanyCount = x.OverallPerformance.GroupCount,
                        Percentile = x.OverallPerformance.Percentile,

                        EnvironmentScore = (int)Math.Round(x.EnvironmentPerformance.Score, MidpointRounding.AwayFromZero),
                        EnvironmentAssessment = new RPAssessment()
                        {
                            Id = x.EnvironmentPerformance.Assessment.Id,
                            Name = x.EnvironmentPerformance.Assessment.Name
                        },
                        SocialScore = (int)Math.Round(x.SocialPerformance.Score, MidpointRounding.AwayFromZero),
                        SocialAssessment = new RPAssessment()
                        {
                            Id = x.SocialPerformance.Assessment.Id,
                            Name = x.SocialPerformance.Assessment.Name
                        },
                        GovernanceScore = (int)Math.Round(x.GovernancePerformance.Score, MidpointRounding.AwayFromZero),
                        GovernanceAssessment = new RPAssessment()
                        {
                            Id = x.GovernancePerformance.Assessment.Id,
                            Name = x.GovernancePerformance.Assessment.Name
                        },
                        IsInReferenceUniverse = x.IsInReferenceUniverse,
                        CategoriesPerformance = new List<CategoryPerformance>()
                        {
                            new CategoryPerformance
                            {
                                CategoryName = "Preparedness",
                                CompanyScore = (int)Math.Round(x.PreparednessScore.Score, MidpointRounding.AwayFromZero),
                            },
                            new CategoryPerformance
                            {
                                CategoryName = "Disclosure",
                                CompanyScore = (int)Math.Round(x.DisclosureScore.Score, MidpointRounding.AwayFromZero),
                            },
                            new CategoryPerformance
                            {
                                CategoryName = "Quantitative Performance",
                                CompanyScore = (int)Math.Round(x.QuantitativePerformanceScore.Score, MidpointRounding.AwayFromZero),
                            },
                            new CategoryPerformance
                            {
                                CategoryName = "Qualitative Performance - Controversies",
                                CompanyScore = (int)Math.Round(x.QualitativePerformanceScore.Score, MidpointRounding.AwayFromZero),
                            }
                        }
                    });
                    companyRelativePositionDictionary = rpPerformanceData.ToDictionary(x => x.Id, x => x.RelativePosition);
                    companyIndicatorsPerformanceDictionary = rpPerformanceData.ToDictionary(x => x.Id, x => x.Indicators);
                    themesPerformanceDic = rpPerformanceData.ToDictionary(x => x.Id, x => new List<ClientDW.Entities.ThemePerformance>()
                    {
                        new ThemePerformance()
                        {
                            ThemeName = "Environment",
                            Score = (int)Math.Round(x.EnvironmentPerformance.Score, MidpointRounding.AwayFromZero),
                            Rank = x.EnvironmentPerformance.Rank.Value ?? 0,
                            Count = x.EnvironmentPerformance.GroupCount,
                            Percentile = x.EnvironmentPerformance.Percentile,
                            Assessment = x.EnvironmentPerformance.Assessment.Name,
                            Weight = x.EnvironmentPerformance.Weight,
                            IsInReferenceUniverse = x.IsInReferenceUniverse
                        },
                        new ThemePerformance()
                        {
                            ThemeName = "Social",
                            Score =(int)Math.Round(x.SocialPerformance.Score, MidpointRounding.AwayFromZero),
                            Rank = x.SocialPerformance.Rank.Value ?? 0,
                            Count = x.SocialPerformance.GroupCount,
                            Percentile = x.SocialPerformance.Percentile,
                            Assessment = x.SocialPerformance.Assessment.Name,
                            Weight = x.SocialPerformance.Weight,
                            IsInReferenceUniverse = x.IsInReferenceUniverse
                        },
                        new ThemePerformance()
                        {
                            ThemeName = "Governance",
                            Score =(int)Math.Round(x.GovernancePerformance.Score, MidpointRounding.AwayFromZero),
                            Rank = x.GovernancePerformance.Rank.Value ?? 0,
                            Count = x.GovernancePerformance.GroupCount,
                            Percentile = x.GovernancePerformance.Percentile,
                            Assessment = x.GovernancePerformance.Assessment.Name,
                            Weight = x.GovernancePerformance.Weight,
                            IsInReferenceUniverse = x.IsInReferenceUniverse
                        }
                    });
                });
                readActions.Add(() =>
                {
                    companyHistoricalPerformanceDic = _historycalDataManager.GetByIds(ids);
                });
                readActions.Add(() =>
                {
                    var all = _repRPIndicatorExt.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();

                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        standardIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repRPControversyInd.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        controversyIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repCompGroupControversy.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        comparisonGroupControversiesDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repEventIndicator.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        eventIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {

                    var all = _repIncident.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();

                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        incidentsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var companyKeyEsgIssues = _repCompanyESGIssue.ReadAllWhere(x => ids.Contains(x.Id)).ToList();
                    keyEsgIssuesDictionary = companyKeyEsgIssues.ToDictionary(kei => kei.Id, kei => kei.KeyESGIssues);
                    subPeerGroupIdDictionary = companyKeyEsgIssues.ToDictionary(kei => kei.Id,
                        kei => kei.SubPeerGroupId);
                });
                readActions.Add(() =>
                {
                    var sources = _repSource.ReadAllWhere(s => ids.Contains(s.CompanyId));
                    companiesNonControversySources = sources.GroupBy(s => s.CompanyId)
                        .ToDictionary(cs => cs.Key, cs => cs.OrderBy(s => s.SourceText).ToList());
                });




                var parallelRunOk = readActions.RunInParallel(_cancelToken, _maxDegreeOfParallelism);

                if (parallelRunOk)
                {
                    var exceptions = new ConcurrentQueue<Exception>();
                    var options = new ParallelOptions() { CancellationToken = _cancelToken, MaxDegreeOfParallelism = _maxDegreeOfParallelism };


                    Parallel.ForEach(ids, options, (Guid id) =>
                    {
                        try
                        {
                            var keyEsgIssues = keyEsgIssuesDictionary.ContainsKey(id) ? keyEsgIssuesDictionary[id] : null;
                            var subPeerGroupId = subPeerGroupIdDictionary.ContainsKey(id)
                                ? subPeerGroupIdDictionary[id]
                                : 0;
                            var subPeerGroupKeyEsgIssues = SubPeerGroupKeyEsgIssueDictionary.ContainsKey(subPeerGroupId) ? SubPeerGroupKeyEsgIssueDictionary[subPeerGroupId] : null;

                            var crdo = new CompanyReportDataOffline
                            {
                                CompanyId = id,
                                ReportType = ReportType.ComprehensiveReport,

                                CorporateData = cdDic[id],
                                FinancialData = finDic[id],

                                CompanyProfile = rpCompanyProfileDic.ContainsKey(id)
                                    ? rpCompanyProfileDic[id]
                                    : null,

                                OverallPerformance = overallPerformanceDic.ContainsKey(id)
                                    ? overallPerformanceDic[id]
                                    : null,
                                IndustryTopPerformers = companyRelativePositionDictionary.ContainsKey(id)
                                    ? companyRelativePositionDictionary[id].TopList.Select(x => new CompanyScore { CompanyId = x.CompanyId, CompanyName = x.CompanyName, Score = x.Score, Rank = x.Rank }).ToList()
                                    : new List<CompanyScore>(),
                                IndustryPeers = companyRelativePositionDictionary.ContainsKey(id)
                                    ? companyRelativePositionDictionary[id].PeersList.Select(x => new CompanyScore { CompanyId = x.CompanyId, CompanyName = x.CompanyName, Score = x.Score }).ToList()
                                    : new List<CompanyScore>(),

                                CompanyHistoricalPerformance = companyHistoricalPerformanceDic.ContainsKey(id)
                                    ? companyHistoricalPerformanceDic[id].Last36Months
                                    : new List<CompanyHistoryData>(),

                                Analyst = AnalystsDictionary.ContainsKey(rpCompanyProfileDic[id].AnalystId) ? AnalystsDictionary[rpCompanyProfileDic[id].AnalystId] : new Analyst(),

                                AnalystCommentary = rpCompanyProfileDic[id].AnalystCommentary,

                                SubPeerGroupKeyEsgIssues = subPeerGroupKeyEsgIssues ?? new List<SubPeerGroupKeyEsgIssue>(),
                                KeyEsgIssues = keyEsgIssues.OrderBy(x => x.SortKey?.Value).ToList() ?? new List<KeyEsgIssue>(),

                                IndicatorTemplates = IndicatorTemplates,

                                ThemesPerformance = themesPerformanceDic.ContainsKey(id)
                                    ? themesPerformanceDic[id]
                                    : new List<ThemePerformance>(),

                                StandardIndicators = standardIndicatorsDic.ContainsKey(id) && companyIndicatorsPerformanceDictionary.ContainsKey(id)
                                    ? standardIndicatorsDic[id]
                                    : new List<RPIndicatorExtended>(),

                                ControversyIndicators = controversyIndicatorsDic.ContainsKey(id)
                                    ? controversyIndicatorsDic[id]
                                    : new List<RPControversyIndicator>(),

                                ComparisonGroupControversies = comparisonGroupControversiesDic.ContainsKey(id)
                                    ? comparisonGroupControversiesDic[id]
                                    : new List<ComparisonGroupControversy>(),

                                EventIndicators = eventIndicatorsDic.Keys.Contains(id)
                                    ? eventIndicatorsDic[id]
                                    : new List<EventIndicator>(),

                                Incidents = incidentsDic.Keys.Contains(id)
                                    ? incidentsDic[id]
                                    : new List<Incident>(),

                                ESGProfile = EsgDefaultProfile,

                                Sources = companiesNonControversySources.ContainsKey(id)
                                    ? companiesNonControversySources[id]
                                    : new List<Source>()
                            };
                            RPIndicatorPerformance[] indicatorsData;

                            if (companyIndicatorsPerformanceDictionary.TryGetValue(id, out indicatorsData))
                            {
                                if (indicatorsData.Length > 0)
                                {
                                    var indicatorsDataDictionary = indicatorsData.ToDictionary(x => x.Code.ToLowerInvariant(), x => x);
                                    crdo.StandardIndicators = crdo.StandardIndicators.Where(x => indicatorsDataDictionary.ContainsKey(x.Template.Number.ToLowerInvariant())).ToList();
                                    foreach (var x in crdo.StandardIndicators)
                                    {
                                        SetStandardIndicatorWeight(indicatorsDataDictionary, x);
                                    }


                                    crdo.ControversyIndicators = crdo.ControversyIndicators.Where(x => indicatorsDataDictionary.ContainsKey(x.Template.Number.ToLowerInvariant())).ToList();
                                    foreach (var x in crdo.ControversyIndicators)
                                    {
                                        SetControversyIndicatorWeight(indicatorsDataDictionary, x);
                                    }
                                }
                            }
                            crdo.IndustryPeersMaxCapitalization = companyRelativePositionDictionary.ContainsKey(id) ? companyRelativePositionDictionary[id].MarketCapRangeTo : 0;
                            crdo.IndustryPeersMinCapitalization = companyRelativePositionDictionary.ContainsKey(id) ? companyRelativePositionDictionary[id].MarketCapRangeFrom : 0;
                            result.Add(crdo);
                        }
                        catch (Exception ex)
                        {
                            exceptions.Enqueue(ex);
                        }
                    });

                    if (exceptions.Count > 0)
                    {

                        foreach (var ex in exceptions)
                            _logAction(ex.ToString());

                        throw new AggregateException(exceptions);
                    }
                }
            }

            return result.ToArray();
        }



        private static void SetStandardIndicatorWeight(
         IReadOnlyDictionary<string, RPIndicatorPerformance> indicatorsData, RPIndicatorExtended x)
        {
            RPIndicatorPerformance indicatorData;
            if (!indicatorsData.TryGetValue(x.Number.ToLowerInvariant(), out indicatorData))
            {
                return;
            }
            x.Weight = indicatorData.Weight.Value;
            x.WeightedScore = indicatorData.WeightedScore.Value;
            x.SelectedAnswer.Score.Value = Convert.ToInt32(indicatorData.RawScore.Value);
        }

        private static void SetControversyIndicatorWeight(
            IReadOnlyDictionary<string, RPIndicatorPerformance> indicatorsData, RPControversyIndicator x)
        {
            RPIndicatorPerformance indicatorData;
            if (!indicatorsData.TryGetValue(x.Template.Number.ToLowerInvariant(), out indicatorData))
            {
                return;
            }
            x.Weight = indicatorData.Weight;
            x.WeightedScore = indicatorData.WeightedScore;
            x.AnswerCategoryScore = Convert.ToInt32(indicatorData.RawScore.Value);
        }

        public IEnumerable<CompanyReportDataOffline> NextControversyOnlyBulk()
        {
            IEnumerable<Guid> ids;
            IDictionary<Guid, CorporateData> cdDic = null;
            IDictionary<Guid, FinancialData> finDic = null;
            IDictionary<Guid, RPCompanyProfile> rpCompanyProfileDic = new Dictionary<Guid, RPCompanyProfile>();
            IDictionary<Guid, OverallPerformance> overallPerformanceDic = new Dictionary<Guid, OverallPerformance>();
            IDictionary<Guid, RPRelativePosition> companyRelativePositionDictionary = new Dictionary<Guid, RPRelativePosition>();
            IDictionary<Guid, RPIndicatorPerformance[]> companyIndicatorsPerformanceDictionary = new Dictionary<Guid, RPIndicatorPerformance[]>();
            IDictionary<Guid, List<ThemePerformance>> themesPerformanceDic = new Dictionary<Guid, List<ThemePerformance>>();
            IDictionary<Guid, CompanyHistoricalPerformance> companyHistoricalPerformanceDic = new Dictionary<Guid, CompanyHistoricalPerformance>();
            IDictionary<Guid, List<RPIndicatorExtended>> standardIndicatorsDic = new Dictionary<Guid, List<RPIndicatorExtended>>();
            IDictionary<Guid, List<RPControversyIndicator>> controversyIndicatorsDic = new Dictionary<Guid, List<RPControversyIndicator>>();
            IDictionary<Guid, List<ComparisonGroupControversy>> comparisonGroupControversiesDic = new Dictionary<Guid, List<ComparisonGroupControversy>>();
            IDictionary<Guid, List<EventIndicator>> eventIndicatorsDic = new Dictionary<Guid, List<EventIndicator>>();
            IDictionary<Guid, List<Incident>> incidentsDic = new Dictionary<Guid, List<Incident>>();
            IDictionary<Guid, List<KeyEsgIssue>> keyEsgIssuesDictionary = new Dictionary<Guid, List<KeyEsgIssue>>();
            IDictionary<Guid, int> subPeerGroupIdDictionary = new Dictionary<Guid, int>();
            IDictionary<Guid, List<Source>> companiesNonControversySources = new Dictionary<Guid, List<Source>>();

            if (IndicatorTemplates == null)
                OneTimeDataRead();

            var result = new ConcurrentBag<CompanyReportDataOffline>();

            IList<CorporateData> list;
            if (_requestedCompanies.IsNullOrEmpty())
            {
                list = _repCorporateData.ReadAllWhere(a => a.ControversyResearchState.ResearchState == ResearchState.ResearchAvailable, _skipControversy, _bulkSizeControversy);
            }
            else
            {
                list =_repCorporateData.ReadAllWhere(a => a.ControversyResearchState.ResearchState == ResearchState.ResearchAvailable && _requestedCompanies.Contains(a.Id),
                    _skipControversy, _bulkSizeControversy);
            }


            if (list != null && list.Any())
            {
                cdDic = list.ToDictionary(x => x.Id);
                ids = cdDic.Keys.OrderBy(x => x);
                _skipControversy += _bulkSizeControversy;


                var readActions = new List<Action>();
                readActions.Add(() =>
                {
                    finDic = _repFinancialData.ReadbyIds(ids);
                });
                readActions.Add(() =>
                {
                    rpCompanyProfileDic = _repRPCompanyProfile.ReadbyIds(ids);
                });
                readActions.Add(() =>
                {
                    var rpPerformanceData =
                        _repRPCompanyESGComputationResult.ReadWhere(x => ids.Contains(x.Id), null,
                            null, null, x => x.Id, x => x.OverallPerformance, x => x.RelativePosition, x => x.Indicators);

                    overallPerformanceDic = rpPerformanceData.ToDictionary(x => x.Id, x => new OverallPerformance
                    {
                        CompanyScore = (int)Math.Round(x.OverallPerformance.Score, MidpointRounding.AwayFromZero),
                        CompanyAssessment = new RPAssessment()
                        {
                            Id = x.OverallPerformance.Assessment.Id,
                            Name = x.OverallPerformance.Assessment.Name
                        },
                        Percentile = x.OverallPerformance.Percentile,

                        IsInReferenceUniverse = x.IsInReferenceUniverse,

                        CategoriesPerformance = new List<CategoryPerformance>()
                        {
                            new CategoryPerformance
                            {
                                CategoryName = "Preparedness",
                            },
                            new CategoryPerformance
                            {
                                CategoryName = "Disclosure",
                            },
                            new CategoryPerformance
                            {
                                CategoryName = "Quantitative Performance",
                           },
                            new CategoryPerformance
                            {
                                CategoryName = "Qualitative Performance - Controversies",
                            }
                        }
                    });
                    companyRelativePositionDictionary = rpPerformanceData.ToDictionary(x => x.Id, x => x.RelativePosition);
                    companyIndicatorsPerformanceDictionary = rpPerformanceData.ToDictionary(x => x.Id, x => x.Indicators);
                    themesPerformanceDic = rpPerformanceData.ToDictionary(x => x.Id, x => new List<ThemePerformance>()
                    {
                        new ThemePerformance()
                        {
                            ThemeName = "Environment",
                        },
                        new ThemePerformance()
                        {
                            ThemeName = "Social",
                        },
                        new ThemePerformance()
                        {
                            ThemeName = "Governance",
                       }
                    });
                });
                readActions.Add(() =>
                {
                    companyHistoricalPerformanceDic =
                        _historycalDataManager.GetByIds(ids);
                });
                readActions.Add(() =>
                {
                    var all = _repRPIndicatorExt.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();

                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        standardIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repRPControversyInd.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        controversyIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repCompGroupControversy.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        comparisonGroupControversiesDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repEventIndicator.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        eventIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {

                    var all = _repIncident.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();

                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        incidentsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var companyKeyEsgIssues = _repCompanyESGIssue.ReadAllWhere(x => ids.Contains(x.Id)).ToList();
                    keyEsgIssuesDictionary = companyKeyEsgIssues.ToDictionary(kei => kei.Id, kei => kei.KeyESGIssues);
                    subPeerGroupIdDictionary = companyKeyEsgIssues.ToDictionary(kei => kei.Id, kei => kei.SubPeerGroupId);
                });
                readActions.Add(() =>
                {
                    var sources = _repSource.ReadAllWhere(s => ids.Contains(s.CompanyId));
                    companiesNonControversySources = sources.GroupBy(s => s.CompanyId).ToDictionary(cs => cs.Key, cs => cs.OrderBy(s => s.SourceText).ToList());
                });



                var parallelRunOk = readActions.RunInParallel(_cancelToken, _maxDegreeOfParallelism);
                if (parallelRunOk)
                {

                    var exceptions = new ConcurrentQueue<Exception>();
                    var options = new ParallelOptions() { CancellationToken = _cancelToken, MaxDegreeOfParallelism = _maxDegreeOfParallelism };
                    Parallel.ForEach(ids, options, (Guid id) =>
                    {

                        try
                        {
                            var keyEsgIssues = keyEsgIssuesDictionary.ContainsKey(id) ? keyEsgIssuesDictionary[id] : null;
                            var subPeerGroupId = subPeerGroupIdDictionary.ContainsKey(id) ? subPeerGroupIdDictionary[id] : 0;
                            var subPeerGroupKeyEsgIssues = SubPeerGroupKeyEsgIssueDictionary.ContainsKey(subPeerGroupId) ? SubPeerGroupKeyEsgIssueDictionary[subPeerGroupId] : null;
                            var rpCompanyProfile = rpCompanyProfileDic.ContainsKey(id) ? rpCompanyProfileDic[id] : null;

                            var crdo = new CompanyReportDataOffline
                            {
                                CompanyId = id,
                                ReportType = ReportType.ControversyReport,

                                CorporateData = cdDic[id],
                                FinancialData = finDic[id],

                                CompanyProfile = rpCompanyProfileDic.ContainsKey(id)
                                    ? rpCompanyProfileDic[id]
                                    : null,

                                OverallPerformance = overallPerformanceDic.ContainsKey(id)
                                    ? overallPerformanceDic[id]
                                    : null,

                                IndustryTopPerformers = companyRelativePositionDictionary.ContainsKey(id)
                                    ? companyRelativePositionDictionary[id].TopList.Select(x => new CompanyScore { CompanyId = x.CompanyId, CompanyName = x.CompanyName, Score = x.Score, Rank = x.Rank }).ToList()
                                    : new List<CompanyScore>(),

                                IndustryPeers = companyRelativePositionDictionary.ContainsKey(id)
                                    ? companyRelativePositionDictionary[id].PeersList.Select(x => new CompanyScore { CompanyId = x.CompanyId, CompanyName = x.CompanyName, Score = x.Score }).ToList()
                                    : new List<CompanyScore>(),

                                CompanyHistoricalPerformance = companyHistoricalPerformanceDic.ContainsKey(id)
                                    ? companyHistoricalPerformanceDic[id].Last36Months
                                    : new List<CompanyHistoryData>(),

                                Analyst = rpCompanyProfile != null && AnalystsDictionary.ContainsKey(rpCompanyProfile.AnalystId) ? AnalystsDictionary[rpCompanyProfile.AnalystId] : new Analyst(),
                                AnalystCommentary = rpCompanyProfileDic.ContainsKey(id) ? rpCompanyProfileDic[id].AnalystCommentary : string.Empty,

                                SubPeerGroupKeyEsgIssues = subPeerGroupKeyEsgIssues ?? new List<SubPeerGroupKeyEsgIssue>(),
                                KeyEsgIssues = keyEsgIssues != null ? keyEsgIssues.OrderBy(x => x.SortKey?.Value).ToList() : new List<KeyEsgIssue>(),

                                IndicatorTemplates = IndicatorTemplates,

                                ThemesPerformance = themesPerformanceDic.ContainsKey(id)
                                    ? themesPerformanceDic[id]
                                    : new List<ThemePerformance>(),

                                StandardIndicators = standardIndicatorsDic.ContainsKey(id)
                                    ? standardIndicatorsDic[id]
                                    : new List<RPIndicatorExtended>(),

                                ControversyIndicators = controversyIndicatorsDic.ContainsKey(id)
                                    ? controversyIndicatorsDic[id]
                                    : new List<RPControversyIndicator>(),

                                ComparisonGroupControversies = comparisonGroupControversiesDic.ContainsKey(id)
                                    ? comparisonGroupControversiesDic[id]
                                    : new List<ComparisonGroupControversy>(),

                                EventIndicators = eventIndicatorsDic.Keys.Contains(id)
                                    ? eventIndicatorsDic[id]
                                    : new List<EventIndicator>(),

                                Incidents = incidentsDic.Keys.Contains(id)
                                    ? incidentsDic[id]
                                    : new List<Incident>(),

                                ESGProfile = EsgDefaultProfile,

                                Sources = companiesNonControversySources.ContainsKey(id)
                                    ? companiesNonControversySources[id]
                                    : new List<Source>()
                            };

                            RPIndicatorPerformance[] indicatorsData;

                            if (companyIndicatorsPerformanceDictionary.TryGetValue(id, out indicatorsData))
                            {
                                if (indicatorsData.Length > 0)
                                {
                                    var indicatorsDataDictionary = indicatorsData.ToDictionary(x => x.Code, x => x);
                                    crdo.StandardIndicators =
                                        crdo.StandardIndicators.Where(
                                            x => indicatorsDataDictionary.ContainsKey(x.Template.Number))
                                            .ToList();

                                    foreach (var x in crdo.StandardIndicators)
                                    {
                                        SetStandardIndicatorWeight(indicatorsDataDictionary, x);
                                    }

                                    crdo.ControversyIndicators =
                                        crdo.ControversyIndicators.Where(
                                            x => indicatorsDataDictionary.ContainsKey(x.Template.Number))
                                            .ToList();

                                    foreach (var x in crdo.ControversyIndicators)
                                    {
                                        SetControversyIndicatorWeight(indicatorsDataDictionary, x);
                                    }
                                }
                            }

                            crdo.IndustryPeersMaxCapitalization = companyRelativePositionDictionary.ContainsKey(id) ? companyRelativePositionDictionary[id].MarketCapRangeTo : 0;
                            crdo.IndustryPeersMinCapitalization = companyRelativePositionDictionary.ContainsKey(id) ? companyRelativePositionDictionary[id].MarketCapRangeFrom : 0;
                            result.Add(crdo);
                        }
                        catch (Exception ex)
                        {
                            exceptions.Enqueue(ex);
                        }
                    });

                    if (exceptions.Count > 0)
                    {

                        foreach (var ex in exceptions)
                            _logAction(ex.ToString());

                        //petre to do apply error policy
                        throw new AggregateException(exceptions);
                    }
                }
            }

            return result;
        }


        public IEnumerable<CompanyReportDataOffline> NextFocusedRatingsOnlyBulk()
        {
            IEnumerable<Guid> ids;
            IDictionary<Guid, CorporateData> cdDic = null;
            IDictionary<Guid, FinancialData> finDic = null;
            IDictionary<Guid, RPCompanyProfile> rpCompanyProfileDic = new Dictionary<Guid, RPCompanyProfile>();
            IDictionary<Guid, OverallPerformance> overallPerformanceDic = new Dictionary<Guid, OverallPerformance>();
            IDictionary<Guid, RPRelativePosition> companyRelativePositionDictionary = new Dictionary<Guid, RPRelativePosition>();
            IDictionary<Guid, RPIndicatorPerformance[]> companyIndicatorsPerformanceDictionary = new Dictionary<Guid, RPIndicatorPerformance[]>();
            IDictionary<Guid, CompanyHistoricalPerformance> companyHistoricalPerformanceDic = new Dictionary<Guid, CompanyHistoricalPerformance>();
            IDictionary<Guid, List<RPIndicatorExtended>> standardIndicatorsDic = new Dictionary<Guid, List<RPIndicatorExtended>>();
            IDictionary<Guid, List<RPControversyIndicator>> controversyIndicatorsDic = new Dictionary<Guid, List<RPControversyIndicator>>();
            IDictionary<Guid, List<ComparisonGroupControversy>> comparisonGroupControversiesDic = new Dictionary<Guid, List<ComparisonGroupControversy>>();
            IDictionary<Guid, List<EventIndicator>> eventIndicatorsDic = new Dictionary<Guid, List<EventIndicator>>();
            IDictionary<Guid, List<Incident>> incidentsDic = new Dictionary<Guid, List<Incident>>();
            IDictionary<Guid, List<KeyEsgIssue>> keyEsgIssuesDictionary = new Dictionary<Guid, List<KeyEsgIssue>>();
            IDictionary<Guid, int> subPeerGroupIdDictionary = new Dictionary<Guid, int>();

            if (IndicatorTemplates == null)
                OneTimeDataRead();

            var result = new ConcurrentBag<CompanyReportDataOffline>();

            IList<CorporateData> list;

            if (_requestedCompanies.IsNullOrEmpty())
            {
                list = MongoDatabaseFactory
                    .GetDatabase(_clientDwUrl)
                    .GetCollection<CorporateData>(typeof(CorporateData).Name)
                    .Find(cd => cd.CoreEsgResearchState.ResearchState == ResearchState.ResearchAvailable)
                    .Skip(_skipFocusedRatings).Limit(_bulkSizeFocusedRatings)
                    .ToList();
            }
            else
            {
                list = MongoDatabaseFactory
                    .GetDatabase(_clientDwUrl)
                    .GetCollection<CorporateData>(typeof(CorporateData).Name)
                    .Find(cd => cd.CoreEsgResearchState.ResearchState == ResearchState.ResearchAvailable && _requestedCompanies.Contains(cd.Id))
                    .Skip(_skipFocusedRatings).Limit(_bulkSizeFocusedRatings)
                    .ToList();
            }

            if (list != null && list.Any())
            {
                cdDic = list.ToDictionary(x => x.Id);
                ids = cdDic.Keys.OrderBy(x => x);
                _skipFocusedRatings += _bulkSizeFocusedRatings;


                var readActions = new List<Action>();
                readActions.Add(() =>
                {
                    finDic = _repFinancialData.ReadbyIds(ids);
                });
                readActions.Add(() =>
                {
                    rpCompanyProfileDic = _repRPCompanyProfile.ReadbyIds(ids);
                });
                readActions.Add(() =>
                {
                    var rpPerformanceData =
                        _repRPCompanyESGComputationResult.ReadWhere(x => ids.Contains(x.Id), null,
                            null, null, x => x.Id, x => x.OverallPerformance, x => x.RelativePosition, x => x.Indicators);

                    overallPerformanceDic = rpPerformanceData.ToDictionary(x => x.Id, x => new OverallPerformance()
                    {
                        CompanyScore = (int)Math.Round(x.OverallPerformance.Score, MidpointRounding.AwayFromZero),
                        CompanyAssessment = new RPAssessment()
                        {
                            Id = x.OverallPerformance.Assessment.Id,
                            Name = x.OverallPerformance.Assessment.Name
                        },
                        Percentile = x.OverallPerformance.Percentile
                    });
                    companyRelativePositionDictionary = rpPerformanceData.ToDictionary(x => x.Id, x => x.RelativePosition);
                    companyIndicatorsPerformanceDictionary = rpPerformanceData.ToDictionary(x => x.Id, x => x.Indicators);
                });
                readActions.Add(() =>
                {
                    companyHistoricalPerformanceDic = _historycalDataManager.GetByIds(ids);
                });
                readActions.Add(() =>
                {
                    var all = _repRPIndicatorExt.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();

                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        standardIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repRPControversyInd.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        controversyIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repCompGroupControversy.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        comparisonGroupControversiesDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var all = _repEventIndicator.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();
                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        eventIndicatorsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {

                    var all = _repIncident.ReadAllWhere(x => ids.Contains(x.CompanyId)).ToList();

                    var groups = all.GroupBy(a => a.CompanyId);
                    foreach (var kv in groups)
                        incidentsDic.Add(kv.Key, kv.ToList());
                });
                readActions.Add(() =>
                {
                    var companyKeyEsgIssues = _repCompanyESGIssue.ReadAllWhere(x => ids.Contains(x.Id)).ToList();

                    foreach (var companyKeyEsgIssue in companyKeyEsgIssues)
                    {
                        foreach (var kei in companyKeyEsgIssue.KeyESGIssues)
                        {
                            kei.KeyEsgIssueIndicators.Sort(KeyEsgIssueIndicatorSorter.Sort);
                        }
                    }

                    keyEsgIssuesDictionary = companyKeyEsgIssues.ToDictionary(kei => kei.Id, kei => kei.KeyESGIssues);
                    subPeerGroupIdDictionary = companyKeyEsgIssues.ToDictionary(kei => kei.Id, kei => kei.SubPeerGroupId);
                });


                var parallelRunOk = readActions.RunInParallel(_cancelToken, _maxDegreeOfParallelism);

                if (parallelRunOk)
                {
                    var exceptions = new ConcurrentQueue<Exception>();
                    var options = new ParallelOptions() { CancellationToken = _cancelToken, MaxDegreeOfParallelism = _maxDegreeOfParallelism };


                    Parallel.ForEach(ids, options, (Guid id) =>
                    {
                        try
                        {
                            var keyEsgIssues = keyEsgIssuesDictionary.ContainsKey(id) ? keyEsgIssuesDictionary[id] : new List<KeyEsgIssue>();
                            var subPeerGroupId = subPeerGroupIdDictionary.ContainsKey(id)
                                ? subPeerGroupIdDictionary[id]
                                : 0;
                            var subPeerGroupKeyEsgIssues = SubPeerGroupKeyEsgIssueDictionary.ContainsKey(subPeerGroupId) ? SubPeerGroupKeyEsgIssueDictionary[subPeerGroupId] : new List<SubPeerGroupKeyEsgIssue>();
                            var analystId = rpCompanyProfileDic.ContainsKey(id) ? rpCompanyProfileDic[id].AnalystId : Guid.Empty;


                            var crdo = new CompanyReportDataOffline
                            {
                                CompanyId = id,
                                ReportType = ReportType.CoreReport,

                                CorporateData = cdDic[id],
                                FinancialData = finDic[id],

                                CompanyProfile = rpCompanyProfileDic.ContainsKey(id)
                                    ? rpCompanyProfileDic[id]
                                    : null,

                                OverallPerformance = overallPerformanceDic.ContainsKey(id)
                                    ? overallPerformanceDic[id]
                                    : null,

                                IndustryTopPerformers = companyRelativePositionDictionary.ContainsKey(id)
                                    ? companyRelativePositionDictionary[id].TopList.Select(x => new CompanyScore { CompanyId = x.CompanyId, CompanyName = x.CompanyName, Score = x.Score, Rank = x.Rank }).ToList()
                                    : new List<CompanyScore>(),

                                IndustryPeers = companyRelativePositionDictionary.ContainsKey(id)
                                    ? companyRelativePositionDictionary[id].PeersList.Select(x => new CompanyScore { CompanyId = x.CompanyId, CompanyName = x.CompanyName, Score = x.Score }).ToList()
                                    : new List<CompanyScore>(),

                                CompanyHistoricalPerformance = companyHistoricalPerformanceDic.ContainsKey(id)
                                    ? companyHistoricalPerformanceDic[id].Last36Months
                                    : new List<CompanyHistoryData>(),

                                Analyst = AnalystsDictionary.ContainsKey(analystId) ? AnalystsDictionary[analystId] : new Analyst(),
                                AnalystCommentary = rpCompanyProfileDic.ContainsKey(id) ? rpCompanyProfileDic[id].AnalystCommentary : string.Empty,

                                SubPeerGroupKeyEsgIssues = subPeerGroupKeyEsgIssues,
                                KeyEsgIssues = keyEsgIssues.OrderBy(x => x.SortKey?.Value).ToList(),

                                IndicatorTemplates = IndicatorTemplates,

                                ThemesPerformance = new List<ThemePerformance>(),

                                StandardIndicators = standardIndicatorsDic.ContainsKey(id) && companyIndicatorsPerformanceDictionary.ContainsKey(id)
                                    ? standardIndicatorsDic[id]
                                    : new List<RPIndicatorExtended>(),

                                ControversyIndicators = controversyIndicatorsDic.ContainsKey(id)
                                    ? controversyIndicatorsDic[id]
                                    : new List<RPControversyIndicator>(),

                                ComparisonGroupControversies = comparisonGroupControversiesDic.ContainsKey(id)
                                    ? comparisonGroupControversiesDic[id]
                                    : new List<ComparisonGroupControversy>(),

                                EventIndicators = eventIndicatorsDic.Keys.Contains(id)
                                    ? eventIndicatorsDic[id]
                                    : new List<EventIndicator>(),

                                Incidents = incidentsDic.Keys.Contains(id)
                                    ? incidentsDic[id]
                                    : new List<Incident>(),

                                ESGProfile = EsgDefaultProfile,

                            };

                            RPIndicatorPerformance[] indicatorsData;

                            if (companyIndicatorsPerformanceDictionary.TryGetValue(id, out indicatorsData))
                            {
                                if (indicatorsData.Length > 0)
                                {
                                    var indicatorsDataDictionary = indicatorsData.ToDictionary(x => x.Code.ToLowerInvariant(), x => x);
                                    crdo.StandardIndicators = crdo.StandardIndicators.Where(x => indicatorsDataDictionary.ContainsKey(x.Template.Number.ToLowerInvariant())).ToList();
                                    foreach (var x in crdo.StandardIndicators)
                                    {
                                        SetStandardIndicatorWeight(indicatorsDataDictionary, x);
                                    }


                                    crdo.ControversyIndicators = crdo.ControversyIndicators.Where(x => indicatorsDataDictionary.ContainsKey(x.Template.Number.ToLowerInvariant())).ToList();
                                    foreach (var x in crdo.ControversyIndicators)
                                    {
                                        SetControversyIndicatorWeight(indicatorsDataDictionary, x);
                                    }
                                }
                            }
                            crdo.IndustryPeersMaxCapitalization = companyRelativePositionDictionary.ContainsKey(id) ? companyRelativePositionDictionary[id].MarketCapRangeTo : 0;
                            crdo.IndustryPeersMinCapitalization = companyRelativePositionDictionary.ContainsKey(id) ? companyRelativePositionDictionary[id].MarketCapRangeFrom : 0;
                            result.Add(crdo);
                        }
                        catch (Exception ex)
                        {
                            exceptions.Enqueue(ex);
                        }
                    });

                    if (exceptions.Count > 0)
                    {

                        foreach (var ex in exceptions)
                            _logAction(ex.ToString());

                        throw new AggregateException(exceptions);
                    }
                }
            }

            return result.ToArray();
        }



    }
}
